// 注意:
// 不要传入空的数组到此接口中
// 不使用 min/max() 这个名称，会和其他平台宏函数重名
#ifndef xpack_math_minimum
#define xpack_math_minimum
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::math_minimum::inc
#include"define/base_type.hpp"
#include"interface/can_compare.hpp"
#include"interface/initializer_list.hpp"
#include"interface/unified_seq.hpp"
#include"macro/xexport.hpp"
#include"macro/xunlikely.hpp"
#include"utils/get_prop_value.hpp"
#include"utils/value_holder.hpp"
#pragma pop_macro("xuser")

namespace mixc::math_minimum::origin{
    template<class type_t>
    // 不使用 type_t const &，因为如果参数是右值，
    // 那么生命周期达不到返回后的位置，这个在编译器开优化模式才能看到，调试模式会隐匿这个问题
    inline type_t minimum(type_t left, type_t right){
        return left < right ? left : right;
    }

    template<class item_t, class list_t = inc::initializer_list<item_t>, class cmp_t = decltype(inc::default_compare<item_t>)>
    requires(inc::can_unified_seqlizex<list_t, item_t> and inc::can_compare<cmp_t, item_t>)
    inline inc::value_holder<item_t> minimumx(list_t && list, cmp_t const & compare = inc::default_compare<item_t>){
        auto ary        = inc::unified_seq<list_t>(list);
        auto len        = ary->length();
        auto i_min      = uxx{};
        xunlikely(len == 0){
            return {};
        }

        for(uxx i = 1; i < len; i++){
            if (compare(ary[i_min], ary[i]) > 0){
                i_min   = i;
            }
        }
        return { ary[i_min], i_min };
    }

    template<class item_t, class list_t = inc::initializer_list<item_t>, class cmp_t = decltype(inc::default_compare<item_t>)>
    requires(inc::can_unified_seqlizex<list_t, item_t> and inc::can_compare<cmp_t, item_t>)
    inline item_t minimum(list_t && list, cmp_t const & compare = inc::default_compare<item_t>){
        return minimumx<item_t, list_t, cmp_t>((list_t &&)list, compare)->value; // 如果数组为空会出现段错误
    }

    // 这是个 dummy 接口，
    // 要求外部使用 inc::xminimum_field(type, field, list); 这种方式调用
    // 不要直接使用 xminimum_field() 宏
    template<class value_t>
    inline decltype(auto) xminimum_field(value_t && value){
        return (value_t &&)value;
    }

    // 同上
    template<class value_t>
    inline decltype(auto) xminimum_fieldx(value_t && value){
        return (value_t &&)value;
    }

    // 根多细节参考 math/maximum.hpp
    #define xminimum_field(TYPE,FIELD,...)                                                                      \
        xminimum_field(                                                                                         \
            ::mixc::math_minimum::inc::get_prop_value(                                                          \
                ::mixc::math_minimum::origin::minimum<TYPE>(__VA_ARGS__, xcmp_field(FIELD, TYPE)) FIELD         \
            )                                                                                                   \
        )

    #define xminimum_fieldx(TYPE,FIELD,...)                                                                     \
        xminimum_fieldx(([&](){                                                                                 \
            auto result = ::mixc::math_minimum::origin::minimumx<TYPE>(__VA_ARGS__, xcmp_field(FIELD, TYPE));   \
            using value_t = decltype(::mixc::math_minimum::inc::get_prop_value(result->value() FIELD));         \
            if (result->is_hold_value){                                                                         \
                auto value = ::mixc::math_minimum::inc::get_prop_value(result->value() FIELD);                  \
                return ::mixc::math_minimum::inc::value_holder<value_t>(value, result->index);                  \
            }                                                                                                   \
            else{                                                                                               \
                return ::mixc::math_minimum::inc::value_holder<value_t>{};                                      \
            }                                                                                                   \
        })())
}

#endif

// 示意外部可以不用包含 xcmp.hpp，可以直接使用
#include"macro/xcmp.hpp"
xexport_space(mixc::math_minimum::origin)